package edu.neu.cs6515.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import javax.xml.bind.JAXBException;

import org.apache.commons.io.IOUtils;

import com.thoughtworks.xstream.XStream;

import edu.neu.cs6515.net.Client;
import edu.neu.cs6515.net.Server;
import edu.neu.cs6515.net.test.integration.RemoteTurnProxyTestRunner;
import edu.neu.cs6515.player.strategy.LowestColorFirstStrategy;
import edu.neu.cs6515.test.runner.BoardTestRunner;
import edu.neu.cs6515.test.runner.PlayerGUITestRunner;
import edu.neu.cs6515.test.runner.PlayerTestRunner;
import edu.neu.cs6515.test.runner.TurnTestRunner;
import edu.neu.cs6515.xml.Board;
import edu.neu.cs6515.xml.False;
import edu.neu.cs6515.xml.Player;
import edu.neu.cs6515.xml.Tile;
import edu.neu.cs6515.xml.XMLTurnProxy;
import edu.neu.cs6515.xml.XMLPlacementSequenceUnmarshaller;
import edu.neu.cs6515.xml.XMLPlayerUnmarshaller;
import edu.neu.cs6515.xml.XMLTurnUnmarshaller;
import edu.neu.cs6515.xml.converter.ActionConverter;
import edu.neu.cs6515.xml.converter.AdministratorConverter;
import edu.neu.cs6515.xml.converter.BoardConverter;
import edu.neu.cs6515.xml.converter.PlacementConverter;
import edu.neu.cs6515.xml.converter.RemoteTurnConverter;
import edu.neu.cs6515.xml.converter.RemoteTurnResultsConverter;
import edu.neu.cs6515.xml.converter.ScoreConverter;
import edu.neu.cs6515.xml.converter.TileConverter;
import edu.neu.cs6515.xml.converter.TurnConverter;
import edu.neu.cs6515.xml.w12.RemoteTurnResults;
import edu.neu.cs6515.xml.w12.Rerack;
import edu.neu.cs6515.xml.w12.True;
import edu.neu.cs6515.xml.w12.TurnTest;

/**
 * Main class that initializes the XML placement test program
 */
public final class GameBootstrap {

    /**
     * Util class, static main method only!
     */
    private GameBootstrap() {
    }

    /**
     * Main Method of the XML placment test program
     * 
     * @param args
     *            are irrelvant, not evaluated
     */
    public static void main(final String[] args) throws JAXBException {
        final BufferedReader in = new BufferedReader(new InputStreamReader(
                System.in));
        try {
            executeTest(args, IOUtils.toString(in));
        } catch (final IOException e) {
            System.out.println("Problem while reading from STDIN");
        }
    }

    /**
     * Executes appropriate test
     * 
     * @param args
     *            cmd line args
     * @param turnDefinition
     *            turn def to be exectued in test
     * @throws IOException
     */
    private static void executeTest(final String[] args,
            final String turnDefinition) throws JAXBException, IOException {
        if (args.length == 1) {
            runTestAccordingToArg(args, turnDefinition);
        } else {
            wrongArgumentInfo();
        }
    }

    /**
     * Print call info
     */
    private static void wrongArgumentInfo() {
        System.out
                .println("Please run the program with one of the following arguments: ");
        System.out.println("BOARD or TURN or PLAYER");
    }

    /**
     * Matches the argument and executes the appropriate test
     * 
     * @param arg
     *            cmd line argument
     * @param turnDefinition
     *            Definition of the turn to be executed
     * @throws IOException
     */
    private static void runTestAccordingToArg(final String[] arg,
            final String turnDefinition) throws JAXBException, IOException {
        if ("BOARD".equals(arg[0])) {
            Board boardFromXML = new XMLPlacementSequenceUnmarshaller()
                    .unmarshall(turnDefinition);
            System.out.println(new BoardTestRunner(boardFromXML)
                    .runGameAndGetResults());
        }
        if ("TURN".equals(arg[0])) {
            XMLTurnProxy turn = new XMLTurnUnmarshaller().unmarshall(turnDefinition);
            System.out.println(new TurnTestRunner(turn).runGameAndGetResults());
        }
        if ("PLAYER".equals(arg[0])) {
            XMLTurnProxy turn = new XMLTurnUnmarshaller().unmarshall(turnDefinition);
            System.out.println(new PlayerTestRunner(turn)
                    .runGameAndGetResults());
        }
        if ("GUI".equals(arg[0])) {
            Player player = new XMLPlayerUnmarshaller()
                    .unmarshall(turnDefinition);
            new PlayerGUITestRunner(player).runAndShowGUI();
        } else if ("HCI".equals(arg[0])) {
            Player player = new XMLPlayerUnmarshaller()
                    .unmarshall(turnDefinition);
            System.out.println(new PlayerGUITestRunner(player).runAndShowHCI());
        } else if ("REMOTE".equals(arg[0])) {
            XStream stream = new XStream();
            stream.alias("turntest", TurnTest.class);
            stream.registerConverter(new RemoteTurnConverter());
            stream.registerConverter(new TurnConverter());
            stream.registerConverter(new ActionConverter());
            stream.registerConverter(new BoardConverter());
            stream.registerConverter(new PlacementConverter());
            stream.registerConverter(new ScoreConverter());
            stream.registerConverter(new TileConverter());
            stream.registerConverter(new AdministratorConverter());
            stream.alias("results", RemoteTurnResults.class);
            stream.alias("true", True.class);
            stream.alias("false", False.class);
            stream.alias("tile", Tile.class);
            stream.alias("rerack", Rerack.class);
            stream.registerConverter(new RemoteTurnResultsConverter());

            TurnTest tt = (TurnTest) stream.fromXML(turnDefinition);

            RemoteTurnProxyTestRunner rtptr = new RemoteTurnProxyTestRunner();

            RemoteTurnResults results = rtptr.runGameAndGetResults(tt);

            String actualOutput = stream.toXML(results);
            System.out.println(actualOutput);
        } else {
            wrongArgumentInfo();
        }
    }
}